/* =====================
 * 文件结构：
 * - main.c
 * - t_cmd_bus.h
 * - t_cmd_bus.c
 * - user_cmds.c
 * ===================== */

/* === 文件：t_cmd_bus.h === */
#ifndef T_CMD_BUS_H
#define T_CMD_BUS_H

#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

#if defined(ENABLE_DEBUG_LOG) && (ENABLE_DEBUG_LOG == 1)
#define BUS_LOG_DEBUG(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
#else
#define BUS_LOG_DEBUG(fmt, ...) do {} while(0)
#endif

#ifndef BUS_SECTION
#   if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__GNUC__)
#       define BUS_SECTION(x) __attribute__((section(x), used))
#   elif defined(__IAR_SYSTEMS_ICC__)
#       define BUS_SECTION(x) @ x
#   else
#       define BUS_SECTION(x)
#   endif
#endif

#ifndef BUS_USED
#   if defined(__GNUC__) || defined(__CC_ARM) || defined(__CLANG_ARM)
#       define BUS_USED __attribute__((used))
#   elif defined(__IAR_SYSTEMS_ICC__)
#       define BUS_USED __root
#   else
#       define BUS_USED
#   endif
#endif

typedef bool (*cmd_bus_callback)(void *param, const char *cmd, char *response, size_t buffer_size);

typedef struct Object_Command_Bus {
    void *param;
    char *cmd_name;
    cmd_bus_callback bus_callback;
    struct Object_Command_Bus *next;
} Object_Command_Bus;

extern Object_Command_Bus *command_bus_list;

void cmd_bus_register(Object_Command_Bus *cmd);
void cmd_bus_cb(const char *cmd, char *response, size_t buffer_size);
size_t get_command_bus_list_length(void);

#define BUS_CMD_ADD(user, name, callback)                                \
    static Object_Command_Bus BUS_CMD_##name = {                         \
        .param = user,                                                   \
        .cmd_name = #name,                                               \
        .bus_callback = callback,                                        \
        .next = NULL                                                     \
    };                                                                   \
    static void BUS_CMD_REG_##name(void) {                               \
        cmd_bus_register(&BUS_CMD_##name);                               \
    }                                                                    \
    BUS_USED static void (*BUS_CMD_##name##_ptr)(void) = BUS_CMD_REG_##name;

void register_all_commands(void);

#ifdef __cplusplus
}
#endif

#endif /* T_CMD_BUS_H */


/* === 文件：t_cmd_bus.c === */
#include "t_cmd_bus.h"

Object_Command_Bus *command_bus_list = NULL;

void cmd_bus_register(Object_Command_Bus *cmd) {
    if (cmd) {
        cmd->next = command_bus_list;
        command_bus_list = cmd;
        BUS_LOG_DEBUG("Command '%s' registered", cmd->cmd_name);
    }
}

static Object_Command_Bus *find_command(const char *name) {
    for (Object_Command_Bus *cmd = command_bus_list; cmd != NULL; cmd = cmd->next) {
        if (strcasecmp(cmd->cmd_name, name) == 0) {
            return cmd;
        }
    }
    return NULL;
}

void cmd_bus_cb(const char *cmd, char *response, size_t buffer_size) {
    if (!cmd || !response) {
        snprintf(response, buffer_size, "cmd is null");
        return;
    }
    Object_Command_Bus *bus = find_command(cmd);
    if (!bus || !bus->bus_callback) {
        snprintf(response, buffer_size, "command not found");
        return;
    }
    if (!bus->bus_callback(bus->param, cmd, response, buffer_size) || response[0] == '\0') {
        snprintf(response, buffer_size, "callback failed or empty");
    }
}

size_t get_command_bus_list_length(void) {
    size_t count = 0;
    Object_Command_Bus *cmd = command_bus_list;
    while (cmd != NULL) {
        count++;
        cmd = cmd->next;
    }
    return count;
}

extern void BUS_CMD_REG_help(void);
void register_all_commands(void) {
    BUS_CMD_REG_help();
}


/* === 文件：user_cmds.c === */
#include "t_cmd_bus.h"

bool help_callback(void *param, const char *cmd, char *response, size_t buffer_size) {
    snprintf(response, buffer_size, "Available commands: help");
    return true;
}

BUS_CMD_ADD(NULL, help, help_callback)


/* === 文件：main.c === */
#include <stdio.h>
#include "t_cmd_bus.h"

int main(void) {
    char resp[128] = {0};

    register_all_commands();

    cmd_bus_cb("help", resp, sizeof(resp));
    printf("Response: %s\n", resp);

    return 0;
}
